Koncepte te tjera te POO
Enkapsulimi
Enkapsulimi ka te beje me menyren sesi ne e deklarojme vizibilitetin e variablave anetare dhe funksioneve anetare te nje klase. Kur ne krijojme nje klase duhet te pyesim vetveten se cilat prej anetareve te klases duhet te jene te aksesueshme nga jashte klases. P.sh. ne rast se kemi nje variabel anetare public $ngjyra
te nje klase Makine
, a eshte e lejueshme qe ketij variabli te jepet vlere nga jashte dmth. $makina1->ngjyra = "E Kuqa"
? Ne rast se dikush krijon nje objekt $makina2
a eshte e lejueshme te aksesoje vleren p.sh. echo $makina1->ngjyra;
?
Anetaret me akses public
Per te vendosur akseset tek variablat dhe funksionet anetare te nje klase perdoren modifikuesit e aksesit (ang. access modifiers) te cilet jane public
, private
dhe protected
.
Ne rast se nuk specifikojme nje modifikues aksesi per nje anetar te klases, atehere si modifikues aksesi default vendoset public
. Nese shihni ne shembujt e mesiperm nuk kemi vendosur modifikues aksesi per funksionet p.sh. kemi deklaruar function ul_shpejtesine($shpejtesia) {...}
dhe jo public function ul_shpejtesine($shpejtesia) {...}
. Ne kete rast eshte e njejta gje sepse kur nuk e specifikojme vendoset aksesi public
.
Anetaret (variabla ose funksione te klases) me modifikues aksesi public
mund te aksesohen ne tre situata te mundshme:
- Brenda klases ku anetaret jane deklaruar
- Jashte klases ku anetaret jane deklaruar
- Brenda klases femije qe trashegon klasen ku anetaret jane deklaruar
Le te marrim nje shembull:
<?php
class Makine {
public $ngjyra = "E Kuqe";
public $shpejtesia = 120;
public function ul_shpejtesine($shpejtesia) {
$this->shpejtesia = $shpejtesia;
}
public function ndalo() {
$this->ul_shpejtesine(80);
$this->ul_shpejtesine(60);
$this->ul_shpejtesine(30);
$this->ul_shpejtesine(0);
}
}
// Jashte klases:
$makina1 = new Makine();
$makina1->ngjyra = "E Zeze";
Ne shembullin e mesiperm duke qene se variabli anetare public $ngjyra
eshte publik, ai mund te aksesohet edhe jashte klases si ne rastin e mesiperm $makina1->ngjyra = "E Zeze"
ku kemi ndryshuar edhe ngjyren.
Funksioni ul_shpejtesine()
perdoret per te ulur shpejtesine e makines sipas vleres qe i kalojme. Por ne te vertete duke qene se variabli anetar public $shpejtesia
eshte publik ne mund ta ulim shpejtesine edhe pa perdorur funksionin e mesiperm thjesht duke ndryshuar variablin $makina1->$shpejtesia = 0;
. Duke pare me kujdes veme re qe ne kete rast edhe funksioni ndalo()
eshte i panevojshem pasi shpejtesia ulet ne zero thjesht duke aksesuar variablin anetare $makina1->$shpejtesia
. Epo kjo nuk eshte gjeja e duhur pasi nuk duhet te lejohet qe shpejtesia te ulet ne menyre te menjehershme nga jashte klases.
Ajo qe na vjen ne ndihme eshte modifikuesi i aksesit private
, me te cilin percaktojme se cilet prej anetareve te klases duhet te jene private, te paaksesueshme jashte klases ku jane deklaruar.
Anetaret me akses private
Anetaret (variabla ose funksione te klases) me modifikues aksesi private
mund te aksesohen ne nje situate te mundshme:
- Brenda klases ku anetaret jane deklaruar
Jashte klases ku anetaret jane deklaruarBrenda klases femije qe trashegon klasen ku anetaret jane deklaruar
Ne menyre qe anetaret $shpejtesia
dhe ul_shpejtesine()
te mos aksesohen jashte klases le ti vendosim aksesin private
:
<?php
class Makine {
private $shpejtesia = 120;
private function ul_shpejtesine($shpejtesia) {
$this->shpejtesia = $shpejtesia;
}
public function ndalo() {
$this->ul_shpejtesine(80);
$this->ul_shpejtesine(60);
$this->ul_shpejtesine(30);
$this->ul_shpejtesine(0);
}
}
// Jashte klases:
$makina1 = new Makine();
//Do te gjeneroje error:
$makina1->shpejtesia = 50;
Ne rastin e mesiperm deklarata $makina1->shpejtesia = 50
do te gjeneroje nje error, pasi nuk na lejohet te aksesojme variablin anetar ne kete menyre. E vetmja gje qe mund te bejme eshte te ndalojme, duke ulur shpejtesine ne menyre graduale, pra te therrasim funksionin $makina1->ndalo()
, pasi vetem ky funksion eshte i aksesueshem nga jashte klases.
Ne rast se nje klase femije trashegon klasen e mesiperme Makine
, klasa femije nuk do te kete akses ne funksionin anetar ul_shpejtesine()
dhe ne variablin anetar $shpejtesia
pasi ata jane te deklaruar private
.
Shembull:
<?php
class Autoveture extends Makine {
public $kilometrazhi = 80;
}
$autoveture = new Autoveture();
//Therret funksionin e trasheguar nga klasa prind
$autoveture->ndalo();
//Do te gjeneroje error:
$autoveture->ul_shpejtesine(30);
Edhe pse klasa Autoveture
trashegon klasen Makine
, ajo nuk mund te perdore anetaret private
te klases prind, dhe deklarata $autoveture->ul_shpejtesine(30)
do te gjeneroje gabim. Ne menyre qe kjo te jete e mundur na vijne ne ndihme modifikuesi i aksesit protected
.
Anetaret me akses protected
Anetaret (variabla ose funksione te klases) me modifikues aksesi protected
mund te aksesohen ne dy situata te mundshme:
- Brenda klases ku anetaret jane deklaruar
Jashte klases ku anetaret jane deklaruar- Brenda klases femije qe trashegon klasen ku anetaret jane deklaruar
Pra, anetaret e deklaruar protected
nuk jane te aksesueshem jashte klases ku jane deklaruar:
<?php
class Makine {
private $shpejtesia = 120;
protected function ul_shpejtesine($shpejtesia) {
$this->shpejtesia = $shpejtesia;
}
public function ndalo() {
$this->ul_shpejtesine(80);
$this->ul_shpejtesine(60);
$this->ul_shpejtesine(30);
$this->ul_shpejtesine(0);
}
}
// Jashte klases:
$makina1 = new Makine();
//Do te gjeneroje error pasi nuk mund te aksesohet jashte klases
$makina1->ul_shpejtesine(50);
Ne deklaraten $makina1->ul_shpejtesine(50)
do te gjenerohet gabim sepse anetari ul_shpejtesine()
nuk mund te aksesohet jashte klases. Por, ne ndryshim nga private
, ne kete rast protected
na lejon qe te perdorim anetaret brenda klasave femije, qe trashegojne klasen ku ata jane deklaruar.
Shembull:
<?php
class Autoveture extends Makine {
public $kilometrazhi = 80;
}
$autoveture = new Autoveture();
//Nuk do te gjeneroje error
$autoveture->ul_shpejtesine(30);
Konstantet
Nje konstante klase eshte nje anetar i klases, pak a shume si nje variabel por eshte e pandryshueshme dhe emri i saj nuk fillon me simbolin $
. Konstantet mund te shoqerohen me modifikuesit e aksesit, por ne rast se nuk i shoqerojme ato jane public
si parazgjedhje (default).
Deklarimi i konstanteve:
<?php
class Punonjes {
const MOSHA_MAKSIMALE = 65;
function printo_moshen_maksimale() {
print 65;
}
}
Konstantet deklarohen me ane te termit const
shoqeruar me emrin e tyre, dhe me pas me vleren. Lind pyetja se si i aksesojme konstantet brenda apo jashte klases.
Perdorimi i konstanteve jashte klases:
<?php
echo Punonjes::MOSHA_MAKSIMALE;
Jashte klases vleren e konstantes mund ta aksesojme duke perdorur emrin e klases shoqeruar me simbolin ::
, dhe me pas emri i konstantes.
Perdorimi i konstanteve brenda klases:
<?php
class Punonjes {
const MOSHA_MAKSIMALE = 65;
function printo_moshen_maksimale() {
//self - i referohet klases aktuale
print self::MOSHA_MAKSIMALE;
}
}
Brenda klases na vjen ne ndihme operatori self
i cili i referohet klases aktuale ku jemi. Pra, pak a shume ne te njejten menyre sic referohen jashte klases por ne vend te emrit te klases perdoret termi self
qe referon klasen aktuale.
Nuk mund te ndryshojme vleren e nje konstanteje pasi ajo eshte deklaruar. Deklarimi Punonjes::MOSHA_MAKSIMALE = 60;
do te gjeneronte nje gabim.
Klasat abstrakte
Klasat abstrakte jane klasa te vecanta prej te cilave nuk mund te krijohen kurre objekte. Ato perdoren me se shumti si klasa prind (superklasa) per klasa te tjera qe i trashegojne. Pra, brenda nje klase abstrakte mund te implementojme nje liste funksionalitetesh, te cilat pasi klasa te trashegohet mund te perdoren nga klasat femije.
Ne shembujt e kaluar permendem nje klase prind Kafshe
dhe dy klasa femije Zog
dhe Qen
. Ne te vertete ne nuk duhet te lejojme qe dikush te krijoje objekte te tipit Kafshe
pasi eshte shume e paspecifikuar. Per kete arsye e deklarojme kete klase abstrakte.
Klasat abstrakte deklarohen me termin abstract
perpara:
<?php
abstract clas Kafshe {
public $ngjyra;
public $madhesia;
function merr_frym() {
print ("Thith oksigjenin qe ndodhet ne ajer.");
}
}
Duke deklaruar kete klase abstrakte, nuk na lejohet te krijojme objekte per kete klase, dhe deklarata $kafshe = new Kafshe();
do te na gjeneronte nje gabim.
Pervec klasave, mund te deklarojme edhe funksione abstrakte abstract function hello() {}
. Ne rast se ne nje klase deklarojme nje funksion abstrakt, atehere edhe vete klasa duhet deklaruar abstrakte. Vetem klasat abstrakte mund te mbajne funksione abstrakte. Trupin e nje funksioni abstrakt mund ta leme bosh. Funksionet abstrakte krijohen per te detyruar klasat femije (qe trashegojne klasen ku eshte deklaruar) qe te implementojne funksionin ne fjale, te ndertojne trupin e ketij funksioni duke shkruajtur kod brenda tij. Ne rast te kundert do te gjenerohet nje error nga PHP-ja. Kur implementohet funksioni ne klasen femije modifikuesi i aksesit nuk duhet te ndryshoje, ai mbetet i njejte perndryshe do te gjenerohet gabim.
Shembull:
<?php
abstract clas Kafshe {
public $ngjyra;
public $madhesia;
public function merr_frym() {
print ("Thith oksigjenin qe ndodhet ne ajer.");
}
abstract public function pershendet() {};
}
Ne klasen femije qe trashegon klasen e mesiperme Kafshe
, jemi te detyruar qe te implementojme funksionin pershendet()
.
<?php
abstract clas Qen extends Kafshe {
//Hiqet termi abstract
public function pershendet() {
print ("Ham Ham");
};
}
$qen = new Qen();
$qen->merr_frym();
$qen->pershendet();
Objekti $qen
mund te perdore si anetaret e trasheguar nga klasa prind, ashtu edhe ato te implementuar brenda klases Qen
.
Nderfaqet (Interfaces)
Nderfaqet deklarohen per te dhene nje liste me emra funksionesh per implementuesit e saj. Nderfaqet jane thjesht nje shabllon qe tregon nje liste me funksione te ndryshme pa trup pra pa kllapat {
dhe }
. Klasat qe implementojne kete nderfaqe jane te detyruara te implementojne te gjitha funksionet e listuara. Nje nderfaqe nuk mund te permbaje variabla anetare, por mund te permbaje konstante dhe funksione anetare. Cdo funksion qe krijohet ne nderfaqe duhet te deklarohe public
dhe nuk mund te kete kod konkret ne brendesi te saj, pasi ata jane pa trup. Nderfaqet deklarohen me ane te termit interface
.
Shembull:
<?php
interface ReceteGatimi
{
public function perberesit();
}
Ne menyre qe te perdorim nje nderfaqe duhet te perdorim termin implements
pas deklarimit te nje klase. Supozojme qe kemi nje klase me emrin Bakllava
:
<?php
class Bakllava implements ReceteGatimi {
//Jemi te detyruar te implementojme nje trup per kete funksion:
public function perberesit() {
print("Miell, Veze, Sheqer, Arra etj...");
};
}
Ashtu si me klasat abstrakte (qe implementuam funksionet abstrakte), jemi te detyruar te implementojme te gjitha funksionet qe ndodhen ne nderfaqe. Nuk mund te krijojme nje objekt nga nje nderfaqe p.sh. deklarimi $recete = new ReceteGatimi()
gjeneron gabim. SHohim qe nderfaqet sherbejne si nje shabllon qe te na informojne se cilat funksione duhet te deklarojme ne klasat qe e perdorin ate.
Ndryshimi ndermjet klasave abstrakte dhe nderfaqeve
Nderfaqet dhe klasat abstrakte jane pak a shume te njejta. Te dyja ndihmojne per krijimin e shablloneve per klasat qe kane nevoje per to. Me poshte listojme disa ndryshime ndermjet tyre:
Funksionet ne klasat abstrakte mund te deklarohen
abstract
ose funksione normale. Nqs. nje funksion deklarohetabstract
, atehere funksioni duhet te implementohet ne klasen femije (qe trashegon klasen ne fjale). Tek nderfaqet te gjitha funksionet jane abstrakte, keshtuqe te gjitha duhet te implementohen ne klasen qe implementon nderfaqen ne fjale.Na lejohet te deklarojme nje funksion
public
,private
oseprotected
ne klasat abstrakte. Ne nderfaqe te gjitha funksionet duhet te jenepublic
.Ne klasat abstrakte na lejohet te krijojme variabla anetare dhe funksione me kod konkret brenda tyre per sa kohe qe nuk jane deklaruar abstrakte. Nje nderfaqe nuk ka variabla anetare, dhe funksionet nuk mund te kene nje trup.
Nje klase mund te trashegoje 1 klase abstrakte, por nje klase mund te implementoje nje numer te pafundem nderfaqesh edhe pse nderfaqet nuk kane lidhje me njera-tjetren.
Nje klase mund te implementoje nje numer te pafundem nderfaqesh duke i ndare ato me presje:
<?php
class Bakllava implements ReceteGatimi, GatimTradicional { ... }
Nje klase mund te trashegoje nje klase prind, dhe te implementoje disa nderfaqe ne te njejten kohe:
<?php
class Bakllava extends Embelsire implements ReceteGatimi, GatimTradicional { ... }
Type Hinting
Deri me tani kemi mesuar disa tipe te dhenash sic jane integer, stringa, array etj, po ashtu shpjeguam objektet si nje tip kompleks. Ne shume raste do te na duhet te dime dhe te jemi te sigurte per tipin e variables qe presim qe te na kaloje si argument ne nje metode specifike te nje klase, ose ne nje funksion te pavarur. Kjo gje perfshin ate cfare quhet 'Type Hinting'.
Shembull:
<?php
function feste(array $pjesmarresit) {
// le te filloje festa...
}
$pjesmarres = array("Alban", "Xhenty", "Erjon", "Brilant");
feste($pjesmarres);
Ne shembullin e mesiperm funksioni feste(...)
pranon vetem nje argument te tipit array, dhe kjo eshte specifikuar duke vendosur perpara emrit te parametrit termin array
, pra array $pjesmarresit
. Ne rast se ne provojme te kalojme ne kete funksion nje numer feste(10);
ose nje string feste("Alban, Xhenty, Erjon, Brilant")
apo cfaredo lloj tipi tjeter qe nuk eshte array
atehere do te gjenerohet nje error nga PHP-ja.
'Type Hinting' perdoret edhe per objektet. Supozojme qe kemi nje klase Student
dhe nje klase Kurs
:
<?php
class Student {
public $emri;
public $mosha;
function __construct($emri) {
$this->emri = $emri;
}
}
class Kurs {
public $emri;
function __construct($emri) {
$this->emri = $emri;
}
}
Ndertojme nje funksion te pavarur i cili regjistron studentet ne nje kurs te caktuar. Duhet te kemi kujdes, pasi argumentet qe duhet te pranoje ky funksion nuk duhet te jene te cfaredoshem, por detyrimisht nje student dhe nje kurs.
<?php
function regjistro(Student $student, Kurs $kurs) {
echo "Studenti " . $student->emri . " u regjistrua ne kursin " . $kurs->emri;
}
Kemi perdorur type hinting per te siguruar qe tipi i argumenteve qe do te kalohen do te jete i duhuri. Student $student
detyron qe argumenti i pare te jete i tipit Student
, dhe Kurs $kurs
detyron qe argumenti i dyte te jete i tipit Kurs
. Ne rast se nuk ndiqet ky rregull atehere do te gjenerohet gabim.
Polimorfizmi
Supozojme qe kemi nje klase Molle
, Dardhe
dhe Portokall
. Ato jane te ndryshme nga njera-tjetra por qendrojne ne te njejten kategori si fruta. Keshtuqe do te ishte e duhur krijimi i nje nderfaqeje te quajtur Frut
, dhe implementimi i kesaj nderfaqeje nga tre klasat Molle
, Dardhe
dhe Portokall
. Ky quhet polimorfizem. Nje grumbull klasash me strukture dhe funksionalitet te ndryshem, por qe te gjitha perdorin te njejten nderfaqe.
Supozojme qe kemi nje nderfaqe te quajtur Llafazan
:
<?php
interface Llafazan {
public function flet_shume();
}
Krijojme dhe dy klasa qe implementojne kete nderfaqe:
<?php
//Klasa Kafshe eshte klasa e perdorur ne shembujt e kaluar
class Qen extends Kafshe implements Llafazan {
public function flet_shume() {
print "Ham, Ham!";
}
}
class Mace extends Kafshe implements Llafazan {
public function flet_shume() {
print "Miau, Miau!";
}
}
Supozojme qe kemi nje funksion te pavarur (jo pjese te ndonje klase) qe pranon nje objekt te tipit Llafazan
, dmth. nje objekt te nje klase qe implementon nderfaqen Llafazan
.
<?php
function testoTeFoluren(Llafazan $llafazan) {
$llafazan->flet_shume();
}
Kemi perdorur 'Type Hinting' duke detyruar qe objekti qe do te kalojme ne funksion te jete i tipit Llafazan
. Pavaresisht se cfare lloj objekti do te kalojme ne funksionin testoTeFoluren()
, mjafton te jete i nje klase qe implementon nderfaqen Llafazan
dhe ai do te therrase funksionin ->flet_shume()
te ketij objekti.
<?php
$qen = new Qen();
testoTeFoluren($qen); //Rezultati: Ham, Ham!
$mace = new Mace();
testoTeFoluren($mace); //Rezultati: Miau, Miau!
Duke futur objekte te ndryshme si input marrim edhe rezultate te ndryshme. Kjo eshte fuqia e polimorfizmit ne POO.
Variablat dhe metodat statike
Variabel apo metode statike konsiderohen ato variabla ose metoda te cilat mund te aksesohen pa nevojen e krijimit te nje objekti. Ne shpjegimet e meparshme qartesuam qe kur krijojme nje objekt te ri, te gjithe anetaret e klases kopjohen ne nje bllok te ri memorie. Objektet kane kopjet e tyre te vecanta, dhe nuk i ngaterrojne me njeri-tjetrin. Ne rast se anetaret jo-statik jane te vecante per cdo objekt, variablat dhe metodat statike nuk kopjohen per cdo objekt te ri qe krijohet. Ato gjenden aty edhe pa krijuar asnje objekt. Edhe ne rast se krijohen disa objekte ato jane aty te vetme. Le te marrim nje shembull me klasen Student
:
<?php
class Student {
public $emri;
public $mosha;
public $numri_studenteve = 0;
function __construct($emri) {
$this->emri = $emri;
$numri_studenteve++;
}
}
Variabli $numri_studenteve
do te mbaje numrin e studenteve te krijuar. Ne momentin qe krijohet nje objek i ri, do te therritet funksioni __construct
. Fillimisht do te ruaje emrin e studentit $this->emri = $emri;
, dhe me pas duke qene se po krijojme nje student te ri do te inkrementoje variablin $numri_studenteve++
.
<?php
$st1 = new Student("Alban Afmeti");
echo $st1->numri_studenteve; //Rezultati: 1
$st2 = new Student("Gentjan Afmeti");
echo $st2->numri_studenteve; //Rezultati: 1
$st3 = new Student("Brilant Afmeti");
echo $st3->numri_studenteve; //Rezultati: 1
Shohim qe pavaresisht se vazhdojme krijojme objekte te reja variabli $numri_studenteve
mban vleren 1
. Arsyeja pse ndodh kjo eshte se secili prej objekteve te mesiperme ka nje kopje te vecante te variablit $numri_studenteve
, keshtuqe nga 0
qe eshte fillimisht, ky variabel merr vleren 1
pasi krijohet objekti. Ne momentin e krijimit te objekteve te tjera, nuk eshte i njejti variabel qe inkrementohet, por eshte nje kopje tjeter e ketij variabli ne objektin tjeter.
Per kete arsye lind nevoja qe objektet te kene dicka te perbashket. Ketu vijne ne ndihme anetaret statik te klases. Transformojme klasen e mesiperme me variabel statik:
<?php
class Student {
public $emri;
public $mosha;
public static $numri_studenteve = 0;
function __construct($emri) {
$this->emri = $emri;
$numri_studenteve++;
}
}
Variablat ose metodat statike aksesohen ashtu si konstantet qe trajtuam me lart. Jashte klases aksesohen duke shkruajtur emrin e klases, shoqeruar me operatorin ::
, dhe me pas emri i variablit ose metodes, Student::$numri_studenteve
. Brenda klases vjen ne ndihme operatori self
, pra self::$numri_studenteve
<?php
$st1 = new Student("Alban Afmeti");
echo Student::$numri_studenteve; //Rezultati: 1
$st2 = new Student("Gentjan Afmeti");
echo Student::$numri_studenteve; //Rezultati: 2
$st3 = new Student("Brilant Afmeti");
echo Student::$numri_studenteve; //Rezultati: 3
Ne kete rast shohim qe ne variablin statik ruhet me te vertete numri i studenteve te krijuar. Ne te njejten menyre perdoren edhe metodat statike:
<?php
class Student {
public $emri;
public $mosha;
private static $numri_studenteve = 0;
function __construct($emri) {
$this->emri = $emri;
$numri_studenteve++;
}
public static function getNumriStudenteve() {
return self::$numri_studenteve;
}
}
Kemi kthyer variablin statik $numri_studenteve
me akses privat
dhe kemi ndertuar metoden statike getNumriStudenteve()
e cila thjeshte na kthen varialin $numri_studenteve
.
<?php
$st1 = new Student("Alban Afmeti");
$st2 = new Student("Gentjan Afmeti");
$st3 = new Student("Brilant Afmeti");
echo Student::getNumriStudenteve(); //Rezultati: 3
Variablat dhe metodat statike mund te perdoren edhe nqs. nuk kemi krijuar asnje objekt. Pasi ato nuk jane pjese e drejperdrejte e objektit por jane pjese e klases.
<?php
//Therrasim metoden statike pa krijuar asnje objekt:
echo Student::getNumriStudenteve(); //Rezultati: 0
Duhet te kemi kujdes pasi variabli special $this
qe mban referencen e objektit aktual nuk mund te perdoret brenda metodave statike. Arsyeja eshte e qarte pasi dukeqenese metodat statike nuk jane pjese e objektit, referenca $this
e objektit aktual eshte i palogjikshem. Metodat statike mund te therriten edhe pa krijuar asnje objekt, keshtuqe nuk ka sens qe te perdoret variabli $this
brenda tyre duke referuar objektin aktual.
<?php
class Student {
private $emri = "Alban Afmeti";
public getEmri() {
return $this->emri;
}
}
$student = new Student();
$student->getEmri();
Perdorimi i $this
ne funksionin getEmri
ka sens sepse ne momentin qe therritet metoda $student->getEmri()
, nje objekt eshte krijuar $student
i cili po therret kete metode, keshtuqe $this
ne ate moment te kohes mban te njejten reference si $student
. Dukeqenese metodat statike nuk therriten nepermjet objekteve, por nepermjet klases atehere $this
nuk eshte se po i referohet ndonje objekti te krijuar, keshtuqe do te jepte gabim. Kjo eshte arsyeja pse nuk perdorim $this
brenda metodave statike, pasi do te gjeneronte nje gabim.
Nga ana tjeter, ne mund te perdorim variablat apo metodat statike brenda metodave jo-statike, si ne rastin e meposhtem:
<?php
class Student {
private $emri = "Alban Afmeti";
public static $kursi = "Programim ne web";
public printo() {
print ("Emri: " . $this->emri . " Kursi: " . self::$kursi);
}
}
$student = new Student();
$student->getEmri();
Kjo nuk do te shkaktonte ndonje problem, pasi anetaret statik jane gjithmone aty te disponueshem per t'i perdorur.
Metodat magjike
PHP-ja na ofron disa metoda magjike te cilat ekzekutohen automatikisht kur nje ngjarje e caktuar ndodh. Funksioni i konstruktorit, te cilin e trajtuam me lart, konsiderohet gjithashtu metode magjike, pasi edhe ai ekzekutohet kur nje ngjarje e caktuar ndodh. Funksioni __construct
ekzekutohet kur krijohet nje objekt i ri. Emri i metodave magjike ne PHP fillon me dy viza poshte __
, per arsye qe te dallohen nga metodat normale. Le te ndertojme nje klase ku te kemi deklaruar edhe disa metoda magjike:
<?php
class Student {
private $emri = "Alban Afmeti";
public static $kursi = "Programim ne web";
public printo() {
print ("Emri: " . $this->emri . " Kursi: " . self::$kursi);
}
public function __get( $name )
{
echo "Variabli $name nuk ekziston!";
}
public function __set( $name, $value )
{
echo "Vlera $value nuk mund te vendoset sepse variabli $name nuk ekziston!";
}
public function __call( $name, $params )
{
echo "Metoda $name nuk ekziston! <br>";
print_r( $params );
}
public function __toString()
{
return 'Emri i objektit eshte ' . $this->emri;
}
public function __clone()
{
echo 'Ju klonuat objektin ' . $this->emri;
}
public function __invoke()
{
echo 'Nuk mund ta therrisni kete objekt si funksion!';
}
public function __destruct()
{
echo 'Objekti u shkaterrua!';
}
}
__get
- Therritet kur ne perpiqemi te aksesojme nje variabel qe nuk ekziston ne klase. Funksioni pranon 1 parameter qe mban emrin e variablit qe ne u perpoqem te aksesojme.
<?php
$student = new Student();
echo $student->mosha;
Dukeqenese objekti i tipit Student
nuk permban ndonje variabel me emrin mosha
, do te therritet automatikisht metoda __get
e klases Student
, dhe si rezultat do te printohet: Variabli mosha nuk ekziston!
__set
- Therritet kur ne perpiqemi t'i japim vlere nje variabli qe nuk ekziston ne klase. Funksioni pranon 2 parametra, i pari mban emrin e variablit dhe i dyti mban vleren qe u perpoqem qe t'i japim.
<?php
$student = new Student();
$student->mosha = 25;
Dukeqenese objekti i tipit Student
nuk permban ndonje variabel me emrin mosha
, do te therritet automatikisht metoda __set
e klases Student
, dhe si rezultat do te printohet: Vlera 25 nuk mund te vendoset sepse variabli mosha nuk ekziston!
__call
- Therritet kur ne perpiqemi te aksesojme nje metode qe nuk ekziston ne klase. Funksioni pranon 2 parametra, ku i pari mban emrin e metodes qe ne u perpoqem te aksesojme, ndersa i dyti eshte nje array qe mban argumentet qe kaluam ne kete metode.
<?php
$student = new Student();
echo $student->getLendet("Fizike", "Informatike");
Dukeqenese objekti i tipit Student
nuk permban ndonje metode me emrin getLendet
, do te therritet automatikisht metoda __call
e klases Student
, dhe si rezultat do te printohet:
Metoda getLendet nuk ekziston!
Array ( [0] => Fizike [1] => Informatike)
__toString
- Therritet kur ne perpiqemi te printojme nje objekt te kesaj klase. Ne rast se deklarojme nje metode te tille ne klase ne duhet te kthejme nje string dhe asgje tjeter.
<?php
$student = new Student();
echo $student;
Dukeqenese objekti $student
po kalohet drejperdrejt si argument i metodes echo
, do te therritet automatikisht metoda __toString
e klases Student
, dhe si rezultat do te printohet: Emri i objektit eshte Alban Afmeti
__clone
- Therritet kur ne perpiqemi te klonojme nje objekt. Per te klonuar nje objekt perdoret termiclone
. Kur klonojme nje objekt ne po krijojme nje objekt te ri me te njejtat variabla dhe metoda si objekti i klonuar. Gjate klonimit ruhen gjithashtu edhe vlerat e variablave, duke na dhene mundesine te ruajme nje kopje te objektit ne nje gjendje te caktuar.
<?php
$student = new Student();
$student2 = clone $student;
Dukeqenese po realizohet nje klonim i objektit $student
, do te therritet automatikisht metoda __clone
e klases Student
, dhe si rezultat do te printohet: Ju klonuat objektin Alban Afmeti
__invoke
- Therritet kur ne perpiqemi te ekzekutojme nje objekt ashtu si nje funksion, duke i shtuar pas emrit te objektit kllapat()
.
<?php
$student = new Student();
$student();
Ne kete rast do te therritet automatikisht metoda __invoke
e klases Student
, dhe si rezultat do te printohet: Nuk mund ta therrisni kete objekt si funksion!
__destruct
- Therritet kur nje objekt shkaterrohet. Objektet shkaterrohen automatikisht kur skripti PHP perfundon. Nese duam te shkaterrojme nje objekt me heret mund te perdorim funksionin e pavarurunset(...)
<?php
$student = new Student();
unset($student);
Ne kete rast do te therritet automatikisht metoda __destruct
e klases Student
, dhe si rezultat do te printohet: Objekti u shkaterrua!
Vargezimi i metodave
Vargezimi i metodave ka te beje me therritjen e metodave njera pas tjetres.
Supozojme qe kemi nje klase Njeri
me 3 metoda ne te:
<?php
class Njeri {
private $shpejtesia = 0; // km/ore
public function ecen() {
$this->shpejtesia = 5;
}
public function vrapon() {
$this->shpejtesia = 15;
}
public function ndalon() {
$this->shpejtesia = 0;
}
}
Per te therritur keto metoda, na duhet te krijojme nje variabel qe mban reference tek nje objekt:
<?php
$njeriu = new Njeri();
Me pas me ane te ketij variabli (qe mban referencen e nje objekti ne memorie) mund te therrasim metodat me ndihmen e operatorit ->
:
<?php
$njeriu->ecen();
$njeriu->vrapon();
$njeriu->ndalon();
Sic e shohim per te therritur keto 3 metoda na jane dashur 3 rreshta kodi. Per te therritur nje metode te nje klase, mjafton te kemi nje reference tek objekti i klases dhe me ane te operatorit ->
mund te therrasim cfaredo lloj metode jo-statike publike te klases. Ne duam te gjejme nje menyre qe t'i therrasim metodat e mesiperme ne forme vargu:
<?php
$njeriu->ecen()->vrapon()->ndalon();
Shohim qe metoden vrapon()
e kemi therritur pas metodes ecen()
. Te njejten gje kemi bere me metoden ndalon()
ku e kemi therritur pas metodes vrapon()
. Por, me lart thame qe per te therritur nje metode te nje klase duhet qe operatori ->
te vije pas nje reference te nje objekti te kesaj klase. Pra, qe metoda vrapon()
te therritet ne menyren e mesiperme duhet qe shprehja $njeriu->ecen()
te jete nje reference tek nje objekt, ose me sakte te ktheje nje objekt. Aktualisht nuk kthen asgje, ndaj per te zgjidhur kete problem ndryshojme permbajtjen e metodes ecen()
:
<?php
public function ecen() {
$this->shpejtesia = 5;
//Kthen objektin aktual
return $this;
}
Mjafton qe te shtojme shprehjen return $this;
, pasi me ane te saj, metoda do te ktheje nje reference te objektit aktual. Ne kete rast, shprehja $njeriu->ecen()
do te ktheje nje reference te objektit aktual. Por, objekti aktual eshte $njeriu
. Pra, shprehja $njeriu->ecen()
kthen nje reference te objektit $njeriu
. Epo atehere zgjidhja u arrit. Meqenese shprehja $njeriu->ecen()
kthen objektin $njeriu
, atehere jemi te lire te therrasim nje metode tjeter ne vazhdim te kesaj shprehje, keshtuqe therrasim metoden vrapon()
. Ky quhet vargezim i metodave. Per te bere te mundur vargezimin tek te gjitha metodat ndryshojme permbajtjen edhe tek metodat e tjera.
<?php
class Njeri {
private $shpejtesia = 0; // km/ore
public function ecen() {
$this->shpejtesia = 5;
return $this;
}
public function vrapon() {
$this->shpejtesia = 15;
return $this;
}
public function ndalon() {
$this->shpejtesia = 0;
return $this;
}
}
Ne kete moment jemi te lire te perdorim vargezimin:
<?php
$njeriu = new Njeri();
$njeriu->ecen()->vrapon()->ndalon();